﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.EnterpriseLibrary.Data;
using System.Data.Common;
using System.Data;

namespace org.maquech.CEeL.Core.EducationalProgram {
    public sealed class EvaluationType : PersistentObject {
        #region Fields and Properties

        /// <summary>
        /// The EvaluationType's name field.
        /// </summary>
        private string name;

        /// <summary>
        /// The EvaluationType's name.
        /// </summary>
        public string Name {
            get {
                return this.name;
            }
            set {
                if ( this.name != value )
                    modifiedDBFields.Add( "name" );
                this.name = value;
            }
        }
        
        /// <summary>
        /// The EvaluationType's name abbreviation field.
        /// </summary>
        private string abbreviation;

        /// <summary>
        /// The EvaluationType's name abbreviation.
        /// </summary>
        public string Abbreviation {
            get {
                return this.abbreviation;
            }
            set {
                if ( this.abbreviation != value )
                    modifiedDBFields.Add( "abbreviation" );
                this.abbreviation = value;
            }
        }

        /// <summary>
        /// Checks if the current instance is valid to be stored in the database.
        /// </summary>
        public override bool IsValid {
            get {
                return  !(this.name == null) && (this.name.Trim() != "")
                    && ( !( this.abbreviation == null ) && ( this.abbreviation.Trim( ) != "" ) );
            }
        }
        #endregion

        #region Constructors
        public EvaluationType ( ) {
            this.id = -1;
            this.name = "";
            this.abbreviation = "";
            this.isNew = true;
        }

        public EvaluationType ( int id, string name, string abbreviation ) {
            this.id = id;
            this.name = name;
            this.abbreviation = abbreviation;
            this.isNew = ( id == -1 );
        }

        public EvaluationType ( string name, string abbreviation )
            : this( -1, name, abbreviation ) {
        }
        #endregion

        #region Methods

        #region System.Object Methods
        /// <summary>
        /// Checks if the object is equal to the current instance.
        /// </summary>
        /// <param name="obj">The object to check for equality</param>
        /// <returns><code>True</code> if the objects are equal, <code>false</code> otherwise.</returns>
        public override bool Equals ( object obj ) {
            if ( obj == null ) {
                return false;
            }
            EvaluationType ev = obj as EvaluationType;
            if ( ( object ) ev == null ) {
                return false;
            }
            return ( this.name == ev.name )
                && ( this.abbreviation == ev.abbreviation );
        }

        /// <summary>
        /// Checks if the AcademicSpacTypee is equal to the current instance.
        /// </summary>
        /// <param name="a">The EvaluationType to check for equality</param>
        /// <returns><code>True</code> if the objects are equal, <code>false</code> otherwise.</returns>
        public bool Equals ( EvaluationType ev ) {
            if ( ( object ) ev == null ) {
                return false;
            }
            return ( this.name == ev.name )
                && ( this.abbreviation == ev.abbreviation );
        }

        public override int GetHashCode ( ) {
            return id.GetHashCode( )
                ^ this.name.GetHashCode( )
                ^ this.abbreviation.GetHashCode( );
        }

        /// <summary>
        /// String representation of the current instance.
        /// </summary>
        /// <returns>A string representation of the current instance.</returns>
        public override string ToString ( ) {
            StringBuilder bldr = new StringBuilder( );
            object [ ] objArr = new object [ ] { this.id, this.abbreviation, this.name };
            bldr.AppendFormat( "[{0} :  {1}] : {2}", objArr );
            return bldr.ToString( );
        }
        #endregion

        /// <summary>
        /// Saves the current instance to the database.
        /// </summary>
        /// <returns><code>True</code> if the object was saved to the database, <code>false</code> otherwise.</returns>
        public override bool Save ( ){
            bool saved = false;
            Database db = DatabaseFactory.CreateDatabase( );
            DbCommand dbCommand;
            string sqlCommand;

            try {
                sqlCommand = "SELECT count(*) = 0 as exists FROM evaluation_types WHERE id = @id OR name ILIKE @name";
                dbCommand = db.GetSqlStringCommand( sqlCommand );
                db.AddInParameter( dbCommand, "@id", DbType.Int32, id );
                db.AddInParameter( dbCommand, "@name", DbType.String, this.name );
                isNew = ( bool ) db.ExecuteScalar( dbCommand );
                if ( isNew ) {
                    sqlCommand = "SELECT nextval('evaluation_types_id_seq')";
                    dbCommand = db.GetSqlStringCommand( sqlCommand );
                    this.id = ( int ) db.ExecuteScalar( dbCommand );

                    sqlCommand = "INSERT INTO evaluation_types ( id, name, abbreviation )"
                       + " VALUES ( @id, @name, @abbreviation )";
                    dbCommand = db.GetSqlStringCommand( sqlCommand );
                    db.AddInParameter( dbCommand, "@id", DbType.Int32, this.id );
                    db.AddInParameter( dbCommand, "@name", DbType.String, this.name );
                    db.AddInParameter( dbCommand, "@abbreviation", DbType.String, this.abbreviation );
                    saved = db.ExecuteNonQuery( dbCommand ) > 0;
                }
                else if ( this.modifiedDBFields.Count > 0 ) {
                    sqlCommand = "UPDATE evaluation_types SET name = @name, abbreviation = @abbreviaton"
                     + " WHERE id = @id";
                    dbCommand = db.GetSqlStringCommand( sqlCommand );
                    db.AddInParameter( dbCommand, "@id", DbType.Int32, this.id );
                    db.AddInParameter( dbCommand, "@name", DbType.String, this.name );
                    db.AddInParameter( dbCommand, "@abbreviation", DbType.String, this.abbreviation );
                    saved = db.ExecuteNonQuery( dbCommand ) > 0;
                }
                else {
                    //No update or insert needed
                    saved = true;
                }
            }
            catch ( Exception e ) {
                saved = false;
                this.errorMessages.Add( "There was an error saving the EvaluationType: " + e.Message );
            }
            return saved;
        }

        /// <summary>
        /// Deletes the current object from the database.
        /// </summary>
        /// <returns><code>True</code> if the object was deleted from the database, <code>false</code> otherwise.</returns>
        public override bool Delete ( ) {
            bool deleted = false;
            Database db = DatabaseFactory.CreateDatabase( );
            DbCommand dbCommand;
            string sqlCommand;
            try {
                sqlCommand = "DELETE FROM evaluation_types WHERE id = @id";
                dbCommand = db.GetSqlStringCommand( sqlCommand );
                db.AddInParameter( dbCommand, "@id", DbType.Int32, this.id );
                deleted = db.ExecuteNonQuery( dbCommand ) >= 0;
            }
            catch ( Exception e ) {
                deleted = false;
                this.errorMessages.Add( "There was an error saving the EvaluationType: " + e.Message );
            }
            return deleted;
        }


        #region Load Methods
        /// <summary>
        /// Loads the EvaluationType with the given <code>id</code>.
        /// </summary>
        /// <param name="id">The EvaluationTypes' id.</param>
        /// <returns>A EvaluationType object with it's information or a null EvaluationType object if the <code>id</code> was not present in the database.</returns>
        public static EvaluationType Load ( int id ) {
            EvaluationType ev = null;
            Database db = DatabaseFactory.CreateDatabase( );
            DbCommand dbCommand;
            string sqlCommand = "SELECT name, abbreviation FROM evaluation_types WHERE id = @id";
            dbCommand = db.GetSqlStringCommand( sqlCommand );
            db.AddInParameter( dbCommand, "@id", DbType.Int32, id );
            try {
                using ( IDataReader rdr = db.ExecuteReader( dbCommand ) ) {
                    if ( rdr.Read( ) ) {
                        ev = new EvaluationType( id, ( string ) rdr [ "name" ], ( string ) rdr [ "abbreviation" ]  );
                        ev.modifiedDBFields.Clear( );
                        ev.ClearMessages( );
                        ev.isNew = false;
                    }
                    rdr.Close( );
                }
            }
            catch ( Exception e ) {
                ev.errorMessages.Add( string.Format( "There was an error loading the EvaluationType with ID {0}: {1}", id.ToString( ), e.Message ) );
            }
            return ev;
        }

        /// <summary>
        /// Loads the EvaluationType with the given <code>name</code>.
        /// </summary>
        /// <param name="id">The EvaluationTypes' name.</param>
        /// <returns>A EvaluationType object with it's information or a null EvaluationType object if the <code>name</code> was not present in the database.</returns>
        public static EvaluationType LoadByName ( string name ) {
            EvaluationType ev = null;
            Database db = DatabaseFactory.CreateDatabase( );
            DbCommand dbCommand;
            string sqlCommand = "SELECT id, name, abbreviation, description FROM evaluation_types WHERE name ILIKE @name";
            dbCommand = db.GetSqlStringCommand( sqlCommand );
            db.AddInParameter( dbCommand, "@name", DbType.String, name );
            try {
                using ( IDataReader rdr = db.ExecuteReader( dbCommand ) ) {
                    if ( rdr.Read( ) ) {
                        ev = new EvaluationType( ( int ) rdr [ "id" ], ( string ) rdr [ "name" ], ( string ) rdr [ "abbreviation" ] );
                        ev.modifiedDBFields.Clear( );
                        ev.ClearMessages( );
                        ev.isNew = false;
                    }
                    rdr.Close( );
                }
            }
            catch ( Exception e ) {
                ev.errorMessages.Add( string.Format( "There was an error loading the EvaluationType {0}: {1}", name, e.Message ) );
            }
            return ev;
        }

        /// <summary>
        /// Checks the database for existence of the EvaluationType with the given <code>id</code>.
        /// </summary>
        /// <param name="id">The EvaluationTypes' id.</param>
        /// <returns><code>True</code> if the evaluationType with the given <code>id</code>exists, <code>false</code> otherwise.</returns>
        public static bool Exists ( int id ) {
            bool exists = false;
            Database db = DatabaseFactory.CreateDatabase( );
            DbCommand dbCommand;
            string sqlCommand = "SELECT count(*) > 0 as exists FROM evaluation_types WHERE id = @id";
            dbCommand = db.GetSqlStringCommand( sqlCommand );
            db.AddInParameter( dbCommand, "@id", DbType.Int32, id );
            exists = ( bool ) db.ExecuteScalar( dbCommand );
            return exists;
        }

        /// <summary>
        /// Checks the database for existence of the EvaluationType with the given <code>name</code>.
        /// </summary>
        /// <param name="name">The EvaluationTypes' name</param>
        /// <returns><code>True</code> if the evaluationType with the given <code>name</code>exists, <code>false</code> otherwise.</returns>
        public static bool ExistsByName ( string name ) {
            bool exists = false;
            Database db = DatabaseFactory.CreateDatabase( );
            DbCommand dbCommand;
            string sqlCommand = "SELECT count(*) > 0 as exists FROM evaluation_types WHERE name ILIKE @name";
            dbCommand = db.GetSqlStringCommand( sqlCommand );
            db.AddInParameter( dbCommand, "@name", DbType.String, name );
            exists = ( bool ) db.ExecuteScalar( dbCommand );
            return exists;
        }

        /// <summary>
        /// Loads all of the EvaluationTypes in the database to a list.
        /// </summary>
        /// <returns>A List containing all of the EvaluationTypes on the database.</returns>
        public static List<EvaluationType> LoadAll ( ) {
            List<EvaluationType> evl = new List<EvaluationType>( );
            Database db = DatabaseFactory.CreateDatabase( );
            DbCommand dbCommand;
            string sqlCommand = "SELECT id, name, abbreviation FROM evaluation_types ORDER BY name";
            dbCommand = db.GetSqlStringCommand( sqlCommand );
            using ( IDataReader rdr = db.ExecuteReader( dbCommand ) ) {
                while ( rdr.Read( ) ) {
                    evl.Add( new EvaluationType( ( int ) rdr [ "id" ], ( string ) rdr [ "name" ], ( string ) rdr [ "abbreviation" ] ) );
                }
                rdr.Close( );
            }
            return evl;
        }
        #endregion

        #endregion
    }
}
